/**
 * 
 */
package org.stars.daostars.core.conditions;

import java.io.Serializable;
import java.util.Map;

import org.stars.config.AppSettings;
import org.stars.daostars.ConstraintOperator;
import org.stars.security.UserIdentity;
import org.stars.util.StringUtility;
import org.stars.util.reflect.BeanUtil;

import bsh.Interpreter;

/**
 * @author Francesco Benincasa (908099)
 * 
 */
public class ConditionConstraint implements Serializable {

	/**
	 * costruttore
	 */
	public ConditionConstraint() {
		negate = false;
		type = ConditionConstraintType.OPERATOR;
	}

	private ConditionConstraintType type;

	/**
	 * @return the type
	 */
	public ConditionConstraintType getType() {
		return type;
	}

	/**
	 * @param type
	 *            the type to set
	 */
	public void setType(ConditionConstraintType type) {
		this.type = type;
	}

	/**
	 * serial id
	 */
	private static final long serialVersionUID = 1365002096933112463L;

	private String name;

	private ConstraintOperator operator;

	private boolean negate;

	private String value;

	private String propertyValue;

	private String expression;

	/**
	 * @return the expression
	 */
	public String getExpression() {
		return expression;
	}

	/**
	 * @param expression
	 *            the expression to set
	 */
	public void setExpression(String expression) {
		this.expression = expression;
	}

	/**
	 * Getter dell'attributo name.
	 * 
	 * @return the name
	 */
	public String getName() {
		return name;
	}

	/**
	 * Setter dell'attributo name.
	 * 
	 * @param name
	 *            the name to set
	 */
	public void setName(String name) {
		this.name = name;
	}

	/**
	 * Getter dell'attributo value.
	 * 
	 * @return the value
	 */
	public String getValue() {
		return value;
	}

	/**
	 * Setter dell'attributo value.
	 * 
	 * @param value
	 *            the value to set
	 */
	public void setValue(String value) {
		this.value = value;
	}

	/**
	 * Recupera il valore di un attributo, indipendentemente dal tipo di
	 * attributo, USER, ATTRIBUTO del BEAN, parametro INDICIZZATO.
	 * 
	 * @param attributeName
	 *            nome dell'attributo
	 * @param user
	 *            user
	 * @param bean
	 *            entity bean
	 * @param params
	 *            array dei parametri
	 * @return valore dell'attributo
	 * @throws Exception
	 *             in caso di errore
	 */
	protected Object getAttributeValue(String attributeName, UserIdentity user, Object bean, Object[] params) throws Exception {
		Object attributeValue;
		if (attributeName.toLowerCase().startsWith("user.")) {
			// 1. proprietà dello user?
			attributeName = attributeName.substring("user.".length());
			attributeValue = null;
			if (user != null) {
				attributeValue = user.getAttribute(attributeName);
			}
		} else if (attributeName.toLowerCase().startsWith("config.")) {
			attributeName = attributeName.substring("config.".length());
			attributeValue = null;
			attributeValue = AppSettings.getInstance().parameter(attributeName);
		} else if (!StringUtility.isInteger(attributeName)) {
			// 2. proprietà attributo dell'entity bean?
			attributeValue = BeanUtil.getPropertyValue(bean, attributeName);
		} else {
			// 3. parametro indicizzato
			int index = Integer.parseInt(attributeName);

			// se siamo oltre le dimensioni dell'array dei parameti, lo
			// impostiamo a null
			if (index < params.length) {
				attributeValue = params[index];
			} else
				attributeValue = null;
		}

		return attributeValue;
	}

	/**
	 * Verifica se le condizioni che regolano la condizione sono verificate
	 * 
	 * @param user
	 *            user
	 * @param bean
	 *            entity bean
	 * @param params
	 *            parametri indicizzati
	 * @return <code>true</code> se condizione verificata, <code>false</code>
	 *         altrimenti
	 * @throws Exception
	 *             in caso di errore
	 */
	public boolean isVerified(UserIdentity user, Object bean, Object[] params, Map<String, String> variables) throws Exception {

		if (type == ConditionConstraintType.OPERATOR) {
			Object tempProperty = null;
			Object tempPropertyValue = null;
			String tempValue = value;

			tempProperty = getAttributeValue(name, user, bean, params);

			if (StringUtility.nvl(propertyValue).length() > 0) {
				tempPropertyValue = getAttributeValue(propertyValue, user, bean, params);
			}

			boolean ret;

			if (tempProperty instanceof String)
				tempProperty = ((String) tempProperty).toLowerCase();
			if (tempPropertyValue instanceof String)
				tempPropertyValue = ((String) tempPropertyValue).toLowerCase();
			if (tempValue instanceof String)
				tempValue = ((String) tempValue).toLowerCase();

			ret = operator.execute(tempProperty, tempPropertyValue, tempValue);
			if (negate)
				ret = !ret;

			return ret;
		} else {
			// interpretiamo il testo del tag expression
			Interpreter i=new Interpreter();
			
			boolean bRet=false;

			try {
				i.set("user",		user);
				i.set("bean", 		bean);
				i.set("params",		params);
				i.set("variables",	variables);
				i.set("config", AppSettings.getInstance());
				bRet=(Boolean)i.eval(expression);							
			} finally {
				
			}
			
			
			return bRet;
		}
	}

	/**
	 * @return the parameterValue
	 */
	public String getPropertyValue() {
		return propertyValue;
	}

	/**
	 * @param propertyValue
	 *            the parameterValue to set
	 */
	public void setPropertyValue(String propertyValue) {
		this.propertyValue = propertyValue;
	}

	/**
	 * @return the negate
	 */
	public boolean isNegate() {
		return negate;
	}

	/**
	 * @param negate
	 *            the negate to set
	 */
	public void setNegate(boolean negate) {
		this.negate = negate;
	}

	/**
	 * @return the operator
	 */
	public ConstraintOperator getOperator() {
		return operator;
	}

	/**
	 * @param operator
	 *            the operator to set
	 */
	public void setOperator(ConstraintOperator operator) {
		this.operator = operator;
	}
}
